function TerrainTessellator() {

}

Object.assign(TerrainTessellator.prototype, {

	process: function (coordSys, vertexs, indexs, message, terrains, local) {
		var vertexsExt = [];
		var indicesExt = [];

		var left = 64;
		var top = 64;
		var width = 4096 + 2 * left;
		var height = 4096 + 2 * top;

		var gridX = 66;
		var gridY = 66;
		var gridX1 = gridX + 1;
		var gridY1 = gridY + 1;

		var segment_width = width / gridX;
		var segment_height = height / gridY;

		var ix, iy;

		var scaleZ = message.scaleZ;
		var hFactor = 1; // 0.00003;
		var hOffset = 0;

		var bounds = coordSys.computeTileBounds (message.z, message.y, message.x);
		let xStep = Math.abs(bounds.right-bounds.left) / 64;
		let yStep = Math.abs(bounds.top-bounds.bottom) / 64;

		// buffers
		for ( iy = 0; iy < gridY1; iy ++ ) {
			var y = -top + iy * segment_height;
			for ( ix = 0; ix < gridX1; ix ++ ) {
				var x = -left + ix * segment_width;

				//--------------
				var h = hFactor * (terrains[iy * gridX1 + ix] + hOffset)*scaleZ; //evelation value
				
				
				/* //cjh,由于要计算ix+2和iy+2，超出了本瓦片的范围，导致地形接边出显示有裂缝，以下代码先注释起来
				var h_l = h, h_r = h, h_b = h, h_t = h, h_r_2 = h, h_t_2;
				
				if ( ix-1 >= 0 )
					h_l = hFactor * (terrains[iy * gridX1 + (ix-1)] + hOffset)*scaleZ;
				if ( ix+1 < gridX1 )
					h_r = hFactor * (terrains[iy * gridX1 + (ix+1)] + hOffset)*scaleZ;

				if ( iy-1 >= 0 )
					h_b = hFactor * (terrains[(iy-1) * gridX1 + ix] + hOffset)*scaleZ;
				if ( iy+1 < gridY1 )
					h_t = hFactor * (terrains[(iy+1) * gridX1 + ix] + hOffset)*scaleZ;
				
				var dx = h_r - h_l;
				var dy = h_t - h_b;
				var grd = Math.sqrt(dx * dx + dy * dy);

				//--------------
				h_l = h, h_r = h, h_b = h, h_t = h, h_r_2 = h, h_t_2;	
				if ( ix+2 < gridX1 )
					h_r = hFactor * (terrains[iy * gridX1 + (ix+2)] + hOffset)*scaleZ;
				else if ( ix+1 < gridX1 )
					h_r = hFactor * (terrains[iy * gridX1 + (ix+1)] + hOffset)*scaleZ;

				if ( iy-1 >= 0 )
					h_b = hFactor * (terrains[(iy-1) * gridX1 + ix+1] + hOffset)*scaleZ;
				if ( iy+1 < gridY1 )
					h_t = hFactor * (terrains[(iy+1) * gridX1 + ix+1] + hOffset)*scaleZ;
				
				dx = h_r - h_l;
				dy = h_t - h_b;
				var grd_r = Math.sqrt(dx * dx + dy * dy);	

				//--------------
				h_l = h, h_r = h, h_b = h, h_t = h, h_r_2 = h, h_t_2;
				if ( ix-1 >= 0 )
					h_l = hFactor * (terrains[(iy+1) * gridX1 + (ix-1)] + hOffset)*scaleZ;
				if ( ix+1 < gridX1 )
					h_r = hFactor * (terrains[(iy+1) * gridX1 + (ix+1)] + hOffset)*scaleZ;

				if ( iy+2 < gridY1 )
					h_t = hFactor * (terrains[(iy+2) * gridX1 + ix+0] + hOffset)*scaleZ;
				else if ( iy+1 < gridY1 )
					h_t = hFactor * (terrains[(iy+1) * gridX1 + ix+0] + hOffset)*scaleZ;

				dx = h_r - h_l;
				dy = h_t - h_b;
				var grd_t = Math.sqrt(dx * dx + dy * dy);
				*/
	
				//cjh，简单的用tangent值代替上面的代码，凹凸效果没原来好。
				var grd  = h;
				var grd_r = h;
				if(h == -9999){ // no value
					h = 0;
					grd_r = 0;
					grd_t = 0;
					grd =  0;
				}
				else{
					if ( ix+1 < gridX1 )
					    grd_r = hFactor * (terrains[iy * gridX1 + (ix+1)] + hOffset)*scaleZ;
					
					if ( iy+1 < gridY1 )
						grd_t = hFactor * (terrains[(iy+1) * gridX1 + ix] + hOffset)*scaleZ;
					
					if(grd_r==-9999 || grd_t==-9999){ // no value
						grd_r = 0;
						grd_t = 0;
						grd =  0;
					}
					else{
						grd_r = Math.tan((grd_r-grd)/xStep);
						grd_t = Math.tan((grd_t-grd)/yStep);
						grd =  0;

					} 
					
				}
				

				var point = new Vector2(x, y);
				coordSys.tileToWorld(message.z, message.y, message.x, point);

				var vertex = {};
				vertex.position = new Vector3(point.x-local.x, point.y-local.y, h);
				vertex.normal = new Vector3(0, 0, 0);
				vertex.uv = new Vector2(ix / gridX, 1 - ( iy / gridY ));
				vertex.local = local;
				vertex.grdnt = new Vector3(grd, grd_r, grd_t);
				vertexsExt.push(vertex);

				if ( 0 < ix && ix < gridX1 - 1 && 0 < iy && iy < gridY1 - 1 ) {
					vertexs.push(vertex);
				}
			}
		}

		// indices
		for ( iy = 0; iy < gridY; iy ++ ) {
			for ( ix = 0; ix < gridX; ix ++ ) {
				var a = ix + gridX1 * iy;
				var b = ix + gridX1 * ( iy + 1 );
				var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
				var d = ( ix + 1 ) + gridX1 * iy;

				// faces
				indicesExt.push( a, b, d );
				indicesExt.push( b, c, d );
			}
		}


		var vA, vB, vC;
		var pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
		var cb = new Vector3(), ab = new Vector3();
		for ( var i = 0, il = indicesExt.length; i < il; i += 3 ) {
			vA = indicesExt[ i + 0 ];
			vB = indicesExt[ i + 1 ];
			vC = indicesExt[ i + 2 ];

			vertexsExt[ vA ].position.copy( pA );
			vertexsExt[ vB ].position.copy( pB );
			vertexsExt[ vC ].position.copy( pC );

			cb.subVectors( pC, pB );
			ab.subVectors( pA, pB );
			cb.crossVectors( cb, ab );

			vertexsExt[ vA ].normal.x += cb.x;
			vertexsExt[ vA ].normal.y += cb.y;
			vertexsExt[ vA ].normal.z += cb.z;

			vertexsExt[ vB ].normal.x += cb.x;
			vertexsExt[ vB ].normal.y += cb.y;
			vertexsExt[ vB ].normal.z += cb.z;

			vertexsExt[ vC ].normal.x += cb.x;
			vertexsExt[ vC ].normal.y += cb.y;
			vertexsExt[ vC ].normal.z += cb.z;
		}


		// for (var i = 0; i < vertexs.length; i++) {
		// 	//vertexs[i].position.z = 0;
		// }

		for ( iy = 0; iy < gridY - 2; iy ++ ) {
			for ( ix = 0; ix < gridX - 2; ix ++ ) {
				var a = ix + (gridX1 - 2) * iy;
				var b = ix + (gridX1 - 2) * ( iy + 1 );
				var c = ( ix + 1 ) + (gridX1 - 2) * ( iy + 1 );
				var d = ( ix + 1 ) + (gridX1 - 2) * iy;

                var ha = vertexs[ a ].position.z;
                var hb = vertexs[ b ].position.z;
                var hc = vertexs[ c ].position.z;
				var hd = vertexs[ d ].position.z;

                // faces
				if(ha !==0 || hb !== 0 || hd !==0){
                    indexs.push( a, b, d );
				}
                if(hb !==0 || hc !== 0 || hd !==0){
                    indexs.push( b, c, d );
				}

			}
		}
		return true;
	},

	toTransferableObjects: function (vertexBuffer, indexBuffer, transferableObjects, flat) {
		var layouts = [];

		var indices = new Uint16Array(indexBuffer.length);
		var vertices = new Float32Array(vertexBuffer.length * 3);
		var normals = new Float32Array(vertexBuffer.length * 3);
		var uvs = new Float32Array(vertexBuffer.length * 2);
		var local = new Float32Array(vertexBuffer.length * 2);
		var grdnts = new Float32Array(vertexBuffer.length * 3);

		for (var j = 0; j < vertexBuffer.length; j++) {
			var vertex = vertexBuffer[j];

			vertices[j * 3 + 0] = vertex.position.x;
			vertices[j * 3 + 1] = vertex.position.y;
			vertices[j * 3 + 2] = vertex.position.z;

			normals[j * 3 + 0] = vertex.normal.x;
			normals[j * 3 + 1] = vertex.normal.y;
			normals[j * 3 + 2] = vertex.normal.z;

			uvs[j * 2 + 0] = vertex.uv.x;
			uvs[j * 2 + 1] = vertex.uv.y;

            local[j * 2 + 0] = vertex.local.x;
			local[j * 2 + 1] = vertex.local.y;
			
			grdnts[j * 3 + 0] = vertex.grdnt.x;
			grdnts[j * 3 + 1] = vertex.grdnt.y;
			grdnts[j * 3 + 2] = vertex.grdnt.z;
		}
		for (var j = 0; j < indexBuffer.length; j++) {
			indices[j] = indexBuffer[j];
		}

		transferableObjects.push(vertices.buffer);
		transferableObjects.push(normals.buffer);
		transferableObjects.push(uvs.buffer);
		transferableObjects.push(local.buffer);
		transferableObjects.push(grdnts.buffer);
		transferableObjects.push(indices.buffer);

		var layout = {
			attribs: [
				{name: 'position', itemSize: 3, normalized: 0, type: 0, index: 0},
				{name: 'normal', itemSize: 3, normalized: 0, type: 0, index: 1},
				{name: 'uv', itemSize: 2, normalized: 0, type: 0, index: 2},
				{name: 'local', itemSize: 2, normalized: 0, type: 0, index: 3},
				{name: 'grdnt', itemSize: 3, normalized: 0, type: 0, index: 4},
			],
			index: {name: 'index', itemSize: 1, normalized: 0, type: 0, index: 5}
		};
		layouts.push(layout);

		return layouts;
	},

} );



